/* ***** BEGIN LICENSE BLOCK *****
 * Version: RCSL 1.0/RPSL 1.0
 *
 * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
 *
 * The contents of this file, and the files included with this file, are
 * subject to the current version of the RealNetworks Public Source License
 * Version 1.0 (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the RealNetworks Community Source License Version 1.0
 * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
 * in which case the RCSL will apply. You may also obtain the license terms
 * directly from RealNetworks.  You may not use this file except in
 * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
 * applicable to this file, the RCSL.  Please see the applicable RPSL or
 * RCSL for the rights, obligations and limitations governing use of the
 * contents of the file.
 *
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the portions
 * it created.
 *
 * This file, and the files included with this file, is distributed and made
 * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 *
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** */

/**************************************************************************************
 * Fixed-point MP3 decoder
 * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com)
 * June 2003
 *
 * bitstream.c - bitstream unpacking, frame header parsing, side info parsing
 **************************************************************************************/

#include "coder.h"
#include "assembly.h"

/**************************************************************************************
 * Function:    SetBitstreamPointer
 *
 * Description: initialize bitstream reader
 *
 * Inputs:      pointer to BitStreamInfo struct
 *              number of bytes in bitstream
 *              pointer to byte-aligned buffer of data to read from
 *
 * Outputs:     filled bitstream info struct
 *
 * Return:      none
 **************************************************************************************/
void SetBitstreamPointer(BitStreamInfo* bsi, int nBytes, unsigned char* buf)
{
    /* init bitstream */
    bsi->bytePtr = buf;
    bsi->iCache = 0;        /* 4-byte unsigned int */
    bsi->cachedBits = 0;    /* i.e. zero bits in cache */
    bsi->nBytes = nBytes;
}

/**************************************************************************************
 * Function:    RefillBitstreamCache
 *
 * Description: read new data from bitstream buffer into bsi cache
 *
 * Inputs:      pointer to initialized BitStreamInfo struct
 *
 * Outputs:     updated bitstream info struct
 *
 * Return:      none
 *
 * Notes:       only call when iCache is completely drained (resets bitOffset to 0)
 *              always loads 4 new bytes except when bsi->nBytes < 4 (end of buffer)
 *              stores data as big-endian in cache, regardless of machine endian-ness
 *
 * TODO:        optimize for ARM
 *              possibly add little/big-endian modes for doing 32-bit loads
 **************************************************************************************/
static __inline void RefillBitstreamCache(BitStreamInfo* bsi)
{
    int nBytes = bsi->nBytes;

    /* optimize for common case, independent of machine endian-ness */
    if (nBytes >= 4) {
        bsi->iCache  = (*bsi->bytePtr++) << 24;
        bsi->iCache |= (*bsi->bytePtr++) << 16;
        bsi->iCache |= (*bsi->bytePtr++) <<  8;
        bsi->iCache |= (*bsi->bytePtr++);
        bsi->cachedBits = 32;
        bsi->nBytes -= 4;
    }
    else {
        bsi->iCache = 0;
        while (nBytes--) {
            bsi->iCache |= (*bsi->bytePtr++);
            bsi->iCache <<= 8;
        }
        bsi->iCache <<= ((3 - bsi->nBytes) * 8);
        bsi->cachedBits = 8 * bsi->nBytes;
        bsi->nBytes = 0;
    }
}

/**************************************************************************************
 * Function:    GetBits
 *
 * Description: get bits from bitstream, advance bitstream pointer
 *
 * Inputs:      pointer to initialized BitStreamInfo struct
 *              number of bits to get from bitstream
 *
 * Outputs:     updated bitstream info struct
 *
 * Return:      the next nBits bits of data from bitstream buffer
 *
 * Notes:       nBits must be in range [0, 31], nBits outside this range masked by 0x1f
 *              for speed, does not indicate error if you overrun bit buffer
 *              if nBits = 0, returns 0 (useful for scalefactor unpacking)
 *
 * TODO:        optimize for ARM
 **************************************************************************************/
unsigned int GetBits(BitStreamInfo* bsi, int nBits)
{
    unsigned int data, lowBits;

    nBits &= 0x1f;                          /* nBits mod 32 to avoid unpredictable results like >> by negative amount */
    data = bsi->iCache >> (31 - nBits);     /* unsigned >> so zero-extend */
    data >>= 1;                             /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */
    bsi->iCache <<= nBits;                  /* left-justify cache */
    bsi->cachedBits -= nBits;               /* how many bits have we drawn from the cache so far */

    /* if we cross an int boundary, refill the cache */
    if (bsi->cachedBits < 0) {
        lowBits = -bsi->cachedBits;
        RefillBitstreamCache(bsi);
        data |= bsi->iCache >> (32 - lowBits);      /* get the low-order bits */

        bsi->cachedBits -= lowBits;         /* how many bits have we drawn from the cache so far */
        bsi->iCache <<= lowBits;            /* left-justify cache */
    }

    return data;
}

/**************************************************************************************
 * Function:    CalcBitsUsed
 *
 * Description: calculate how many bits have been read from bitstream
 *
 * Inputs:      pointer to initialized BitStreamInfo struct
 *              pointer to start of bitstream buffer
 *              bit offset into first byte of startBuf (0-7)
 *
 * Outputs:     none
 *
 * Return:      number of bits read from bitstream, as offset from startBuf:startOffset
 **************************************************************************************/
int CalcBitsUsed(BitStreamInfo* bsi, unsigned char* startBuf, int startOffset)
{
    int bitsUsed;

    bitsUsed  = (bsi->bytePtr - startBuf) * 8;
    bitsUsed -= bsi->cachedBits;
    bitsUsed -= startOffset;

    return bitsUsed;
}

/**************************************************************************************
 * Function:    CheckPadBit
 *
 * Description: check whether padding byte is present in an MP3 frame
 *
 * Inputs:      MP3DecInfo struct with valid FrameHeader struct
 *                (filled by UnpackFrameHeader())
 *
 * Outputs:     none
 *
 * Return:      1 if pad bit is set, 0 if not, -1 if null input pointer
 **************************************************************************************/
int CheckPadBit(MP3DecInfo* mp3DecInfo)
{
    FrameHeader* fh;

    /* validate pointers */
    if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS)
        return -1;

    fh = ((FrameHeader*)(mp3DecInfo->FrameHeaderPS));

    return (fh->paddingBit ? 1 : 0);
}

/**************************************************************************************
 * Function:    UnpackFrameHeader
 *
 * Description: parse the fields of the MP3 frame header
 *
 * Inputs:      buffer pointing to a complete MP3 frame header (4 bytes, plus 2 if CRC)
 *
 * Outputs:     filled frame header info in the MP3DecInfo structure
 *              updated platform-specific FrameHeader struct
 *
 * Return:      length (in bytes) of frame header (for caller to calculate offset to
 *                first byte following frame header)
 *              -1 if null frameHeader or invalid header
 *
 * TODO:        check for valid modes, depending on capabilities of decoder
 *              test CRC on actual stream (verify no endian problems)
 **************************************************************************************/
int UnpackFrameHeader(MP3DecInfo* mp3DecInfo, unsigned char* buf)
{

    int verIdx;
    FrameHeader* fh;

    /* validate pointers and sync word */
    if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || (buf[0] & SYNCWORDH) != SYNCWORDH || (buf[1] & SYNCWORDL) != SYNCWORDL)
        return -1;

    fh = ((FrameHeader*)(mp3DecInfo->FrameHeaderPS));

    /* read header fields - use bitmasks instead of GetBits() for speed, since format never varies */
    verIdx =         (buf[1] >> 3) & 0x03;
    fh->ver =        (MPEGVersion)( verIdx == 0 ? MPEG25 : ((verIdx & 0x01) ? MPEG1 : MPEG2) );
    fh->layer = 4 - ((buf[1] >> 1) & 0x03);     /* easy mapping of index to layer number, 4 = error */
    fh->crc =   1 - ((buf[1] >> 0) & 0x01);
    fh->brIdx =      (buf[2] >> 4) & 0x0f;
    fh->srIdx =      (buf[2] >> 2) & 0x03;
    fh->paddingBit = (buf[2] >> 1) & 0x01;
    fh->privateBit = (buf[2] >> 0) & 0x01;
    fh->sMode =      (StereoMode)((buf[3] >> 6) & 0x03);      /* maps to correct enum (see definition) */
    fh->modeExt =    (buf[3] >> 4) & 0x03;
    fh->copyFlag =   (buf[3] >> 3) & 0x01;
    fh->origFlag =   (buf[3] >> 2) & 0x01;
    fh->emphasis =   (buf[3] >> 0) & 0x03;

    /* check parameters to avoid indexing tables with bad values */
    if (fh->srIdx == 3 || fh->layer == 4 || fh->brIdx == 15)
        return -1;

    fh->sfBand = &sfBandTable[fh->ver][fh->srIdx];  /* for readability (we reference sfBandTable many times in decoder) */
    if (fh->sMode != Joint)     /* just to be safe (dequant, stproc check fh->modeExt) */
        fh->modeExt = 0;

    /* init user-accessible data */
    mp3DecInfo->nChans = (fh->sMode == Mono ? 1 : 2);
    mp3DecInfo->samprate = samplerateTab[fh->ver][fh->srIdx];
    mp3DecInfo->nGrans = (fh->ver == MPEG1 ? NGRANS_MPEG1 : NGRANS_MPEG2);
    mp3DecInfo->nGranSamps = ((int)samplesPerFrameTab[fh->ver][fh->layer - 1]) / mp3DecInfo->nGrans;
    mp3DecInfo->layer = fh->layer;
    mp3DecInfo->version = fh->ver;

    /* get bitrate and nSlots from table, unless brIdx == 0 (free mode) in which case caller must figure it out himself
     * question - do we want to overwrite mp3DecInfo->bitrate with 0 each time if it's free mode, and
     *  copy the pre-calculated actual free bitrate into it in mp3dec.c (according to the spec,
     *  this shouldn't be necessary, since it should be either all frames free or none free)
     */
    if (fh->brIdx) {
        mp3DecInfo->bitrate = ((int)bitrateTab[fh->ver][fh->layer - 1][fh->brIdx]) * 1000;

        /* nSlots = total frame bytes (from table) - sideInfo bytes - header - CRC (if present) + pad (if present) */
        mp3DecInfo->nSlots = (int)slotTab[fh->ver][fh->srIdx][fh->brIdx] -
                             (int)sideBytesTab[fh->ver][(fh->sMode == Mono ? 0 : 1)] -
                             4 - (fh->crc ? 2 : 0) + (fh->paddingBit ? 1 : 0);
    }

    /* load crc word, if enabled, and return length of frame header (in bytes) */
    if (fh->crc) {
        fh->CRCWord = ((int)buf[4] << 8 | (int)buf[5] << 0);
        return 6;
    }
    else {
        fh->CRCWord = 0;
        return 4;
    }
}

/**************************************************************************************
 * Function:    UnpackSideInfo
 *
 * Description: parse the fields of the MP3 side info header
 *
 * Inputs:      MP3DecInfo structure filled by UnpackFrameHeader()
 *              buffer pointing to the MP3 side info data
 *
 * Outputs:     updated mainDataBegin in MP3DecInfo struct
 *              updated private (platform-specific) SideInfo struct
 *
 * Return:      length (in bytes) of side info data
 *              -1 if null input pointers
 **************************************************************************************/
int UnpackSideInfo(MP3DecInfo* mp3DecInfo, unsigned char* buf)
{
    int gr, ch, bd, nBytes;
    BitStreamInfo bitStreamInfo, *bsi;
    FrameHeader* fh;
    SideInfo* si;
    SideInfoSub* sis;

    /* validate pointers and sync word */
    if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || !mp3DecInfo->SideInfoPS)
        return -1;

    fh = ((FrameHeader*)(mp3DecInfo->FrameHeaderPS));
    si = ((SideInfo*)(mp3DecInfo->SideInfoPS));

    bsi = &bitStreamInfo;
    if (fh->ver == MPEG1) {
        /* MPEG 1 */
        nBytes = (fh->sMode == Mono ? SIBYTES_MPEG1_MONO : SIBYTES_MPEG1_STEREO);
        SetBitstreamPointer(bsi, nBytes, buf);
        si->mainDataBegin = GetBits(bsi, 9);
        si->privateBits =   GetBits(bsi, (fh->sMode == Mono ? 5 : 3));

        for (ch = 0; ch < mp3DecInfo->nChans; ch++)
            for (bd = 0; bd < MAX_SCFBD; bd++)
                si->scfsi[ch][bd] = GetBits(bsi, 1);
    }
    else {
        /* MPEG 2, MPEG 2.5 */
        nBytes = (fh->sMode == Mono ? SIBYTES_MPEG2_MONO : SIBYTES_MPEG2_STEREO);
        SetBitstreamPointer(bsi, nBytes, buf);
        si->mainDataBegin = GetBits(bsi, 8);
        si->privateBits =   GetBits(bsi, (fh->sMode == Mono ? 1 : 2));
    }

    for(gr = 0; gr < mp3DecInfo->nGrans; gr++) {
        for (ch = 0; ch < mp3DecInfo->nChans; ch++) {
            sis = &si->sis[gr][ch];                     /* side info subblock for this granule, channel */

            sis->part23Length =    GetBits(bsi, 12);
            sis->nBigvals =        GetBits(bsi, 9);
            sis->globalGain =      GetBits(bsi, 8);
            sis->sfCompress =      GetBits(bsi, (fh->ver == MPEG1 ? 4 : 9));
            sis->winSwitchFlag =   GetBits(bsi, 1);

            if(sis->winSwitchFlag) {
                /* this is a start, stop, short, or mixed block */
                sis->blockType =       GetBits(bsi, 2);     /* 0 = normal, 1 = start, 2 = short, 3 = stop */
                sis->mixedBlock =      GetBits(bsi, 1);     /* 0 = not mixed, 1 = mixed */
                sis->tableSelect[0] =  GetBits(bsi, 5);
                sis->tableSelect[1] =  GetBits(bsi, 5);
                sis->tableSelect[2] =  0;                   /* unused */
                sis->subBlockGain[0] = GetBits(bsi, 3);
                sis->subBlockGain[1] = GetBits(bsi, 3);
                sis->subBlockGain[2] = GetBits(bsi, 3);

                /* TODO - check logic */
                if (sis->blockType == 0) {
                    /* this should not be allowed, according to spec */
                    sis->nBigvals = 0;
                    sis->part23Length = 0;
                    sis->sfCompress = 0;
                }
                else if (sis->blockType == 2 && sis->mixedBlock == 0) {
                    /* short block, not mixed */
                    sis->region0Count = 8;
                }
                else {
                    /* start, stop, or short-mixed */
                    sis->region0Count = 7;
                }
                sis->region1Count = 20 - sis->region0Count;
            }
            else {
                /* this is a normal block */
                sis->blockType = 0;
                sis->mixedBlock = 0;
                sis->tableSelect[0] =  GetBits(bsi, 5);
                sis->tableSelect[1] =  GetBits(bsi, 5);
                sis->tableSelect[2] =  GetBits(bsi, 5);
                sis->region0Count =    GetBits(bsi, 4);
                sis->region1Count =    GetBits(bsi, 3);
            }
            sis->preFlag =           (fh->ver == MPEG1 ? GetBits(bsi, 1) : 0);
            sis->sfactScale =        GetBits(bsi, 1);
            sis->count1TableSelect = GetBits(bsi, 1);
        }
    }
    mp3DecInfo->mainDataBegin = si->mainDataBegin;  /* needed by main decode loop */

    ASSERT(nBytes == CalcBitsUsed(bsi, buf, 0) >> 3);

    return nBytes;
}

